System interaction
Environment
R 中词法作用域的机理通过环境实现。
函数优先在内部环境搜索用到的变量,搜索不到时,就到上一级环境搜索。
每加载一个扩展包,这个包的环境都会插入搜索路径,并位于全局环境之前。
ls()/objects() |
列出当前工作空间的所有对象 |
ls.str(mode=, pattern=) |
显示当前环境的结构。mode 参数过滤对象类型,pattern
参数为正则表达式,过滤对象名 |
rm() |
删除一个或更多个对象。 |
rm(list=ls(all=TRUE)) |
删除所有对象 |
getOption() |
查看全局选项 |
options() |
设定全局选项。如 digits=7, 设定显示数字的位数。warn=0,
可以改为1,在警告产生时立即显示。 |
Path
dir.create() |
创建一个目录 |
getwd()/setwd() |
查看/设定当前工作目录 |
Memory
tracemem()查看对象的内存地址
Time
Sys.sleep()
使程序暂停若干秒,一般用于某些循环(爬虫、动画等),故意降低运行频率
sys.time() 读取系统时间
t1 <- Sys.time()
...
t2 <- Sys.time()
print(t2 - t1) # 中间代码的运行时间
Help
help(functionName)或?functionName |
查看一个函数的用法 |
example(functionName) |
运行帮主文件中的例子 |
help.search(keyword)或??keyword |
在==所有包==的文档中搜索关键词 |
help(package = "") |
查看一个包的帮助 |
help(options) |
显示可用选项的说明 |
options() |
显示或设置当前选项 |
History
history(#) |
显示最近使用过的#个命令(默认值为25) |
savehistory("myfile") |
保存命令历史到文件myfile中(默认值为.Rhistory) |
loadhistory("myfile") |
载入一个命令历史文件(默认值为.Rhistory) |
Modularization
R Package
install.packages("package") |
安装包 |
installed.packages() |
返回一个字符串矩阵,内含所有已安装的包的多项信息 |
library() |
无参数时,显示库中已经安装了哪些包 |
library(package) |
有参数时,载入包 |
unloadNamespace(package) |
解除载入一个包 |
search() |
查看环境中已经加载了哪些包 |
getOption('defaultPackages') |
查看默认加载的 R 包 |
update.packages("package") |
升级包。若不填入参数,则自动升级所有可以升级的包 |
package::function() |
调用相应包的函数(有时多个包用同一个名字命名不同的函数,会发生冲突,只能这样引用) |
data() |
查看所有预先提供的数据 |
data(package="") |
查看某个包所有预先提供的数据 |
data(dataset_name, package=) |
读入包中数据 |
installed.packages() %>% View()

新装 R 时安装常用包
# 重装 R 前把已安装包的名称(第一列)存为一个 .rds 文件
installed.packages()[, 1] %>%
saveRDS("./download-packages.rds")
# 重装 R 后读取该文件,并安装这些 packages
readRDS("./download-packages.rds") %>%
install.packages()
查看包的流行程度
# 查看 R 包的下载次数
library(cranlogs)
fashion <- function(package_name) {
d <- cran_downloads(
package = package_name,
from = "2022-01-01",
to = "2022-03-31"
)
sum(d$count)
}
fashion('ggplot2')
#> [1] 6591799
fashion("tidyverse")
#> [1] 2414103
fashion("data.table")
#> [1] 2512297
fashion("plotly")
#> [1] 916778
R Script
最佳实践
由于 R 的懒加载特性,模块中的代码不会运行,故 .R
脚本文件作为模块时,不必加载配置常量和包,纯写函数即可,所有的包和配置由主文件加载。
Code Style
Google R Style
一般性规则
- 尽量避免使用
attach(), detach()
- Error 应该使用
Stop()来抛出
- S3 类和 S4 类的函数不要一起使用
命名
对象命名以句号.分隔,不用下划线
函数名首字母大写,驼峰式命名法,不用句号分隔
注释
注释行以#开头,后加一个空格
代码行内短注释需要在代码后面空两格,然后#,再加一个空格
对变量和函数的说明写在它们的上方(紧邻),VSCode 的 R
插件能够自动识别
总体布局与顺序
- 版权声明
- 作者信息
- 文件说明, 包括程序的目的,输入以及输出
- source() 和 library() 说明
- 函数定义
- 可执行语句, 如果有的话 (例如, print, plot)
单元测试应在另一个独立的的文件中进行
IDE
Rstudio
R
Studio cheatsheet 预览:
Shortcuts
| Ctrl + Shift + A |
选中部分行后,格式化代码 |
| Ctrl + Alt + I |
Insert chunk |
| Alt + - |
插入 <- |
| Ctrl + Shift + M |
插入%>% |
| Alt + Shift + K |
显示快捷键 |
| Ctrl + Shift + N |
新建脚本 .r文件 |
Ctrl + Enter Ctrl + Shift + Enter Ctrl + Alt + R |
运行一行代码 运行代码块 运行全部代码 |
| Shift + Home/End |
选中光标到行首/末之间的部分 |
| Tab / Ctrl+Space |
自动补齐 输入完函数名,按tab,自动添加开括号(和闭括号)。 |
| Ctrl + Shift + C |
注释/取消注释 |
| F1 |
查看帮助 |
| Ctrl+ ↑ |
在 Console 中输入“xxx”,然后按 Ctrl+
↑。就可以列出所有输入过的以“xxx”开头的命令。 |
VSCode
优点
- 鼠标悬停,即可显示变量的定义信息和函数的帮助文档(仅限 R
包中函数的官方文档和本文件中自定义函数的定义,无法显示引入模块中的自定义函数的定义),省去了查阅文档的大量时间
- 保存(
Ctrl+S)时自动格式化
Ctrl+Enter自动运行一行,Ctrl+Shift+Enter自动运行当前文件
配置步骤
安装 R 包 languageserver
install.packages("languageserver")
在 VSCode 扩展商店中安装 R 插件。
- 安装完成后在 VSCode
设置中搜索
r.rterm.option,删除--no-save,--no-restore,添加--no-site-file和
R.exe
的路径--r-binary=C:\Program Files\R\R-4.1.3\bin\R.exe
安装 Radian:一款现代的 R console,它是用 Python 编写的
安装完成后在 cmd 中输入 radian
查看是否安装成功。
若出现 “cannot determine R
HOME”,可能存在多个R路径(如新安装了4.1.2版本),而 Radian
无法识别。解决这个问题的方法仍然是在 VSCode 中设置 R.exe
的路径。除了搜索r.rterm.option进行修改,也可以在设置界面的右上角打开
setting.json文件直接修改:
"r.rterm.option": [
"--no-site-file",
"--r-binary=C:\\Program Files\\R\\R-4.1.3\\bin\\R.exe"
],
VSCode 中 Radian 相关设置
- 搜索
r.rterm.windows,将其设置为 radian.exe 的路径。在
cmd 中(powershell 不行)输入 where radian
可以获取其路径。
- 搜索
R: Bracketed Paste并勾选,否则 Radian 不会启用
- 搜索
r.sessionWatcher并勾选
如何在
VSCODE 中高效使用 R 语言 (图文详解)_Baimoc-CSDN博客
LS0tDQp0aXRsZTogIlIgRW5naW5lZXJpbmciDQpzdWJ0aXRsZTogJ1N5c3RlbSwgTW9kdWxhcml6YXRpb24sIENvZGUgU3R5bGUgYW5kIElERScNCmF1dGhvcjogIkh1bW9vbiINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDogaHRtbF9kb2N1bWVudA0KZG9jdW1lbnRjbGFzczogY3RleGFydA0KY2xhc3NvcHRpb246IGh5cGVycmVmLA0KLS0tDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCnNvdXJjZSgiLi4vUm1hcmtkb3duLXRlbXBsYXRlL1JtYXJrZG93bl9jb25maWcuUiIpDQoNCiMjIGdsb2JhbCBvcHRpb25zID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIHdpZHRoID0gY29uZmlnJHdpZHRoLA0KICBmaWcud2lkdGggPSBjb25maWckZmlnLndpZHRoLA0KICBmaWcuYXNwID0gY29uZmlnJGZpZy5hc3AsDQogIG91dC53aWR0aCA9IGNvbmZpZyRvdXQud2lkdGgsDQogIGZpZy5hbGlnbiA9IGNvbmZpZyRmaWcuYWxpZ24sDQogIGZpZy5wYXRoID0gY29uZmlnJGZpZy5wYXRoLA0KICBmaWcuc2hvdyA9IGNvbmZpZyRmaWcuc2hvdywNCiAgd2FybiA9IGNvbmZpZyR3YXJuLA0KICB3YXJuaW5nID0gY29uZmlnJHdhcm5pbmcsDQogIG1lc3NhZ2UgPSBjb25maWckbWVzc2FnZSwNCiAgZWNobyA9IGNvbmZpZyRlY2hvLA0KICBldmFsID0gY29uZmlnJGV2YWwsDQogIHRpZHkgPSBjb25maWckdGlkeSwNCiAgY29tbWVudCA9IGNvbmZpZyRjb21tZW50LA0KICBjb2xsYXBzZSA9IGNvbmZpZyRjb2xsYXBzZSwNCiAgY2FjaGUgPSBjb25maWckY2FjaGUsDQogIGNhY2hlLmNvbW1lbnRzID0gY29uZmlnJGNhY2hlLmNvbW1lbnRzLA0KICBhdXRvZGVwID0gY29uZmlnJGF1dG9kZXANCikNCmBgYA0KDQojIyBTeXN0ZW0gaW50ZXJhY3Rpb24NCg0KIyMjIEVudmlyb25tZW50DQoNClIg5Lit6K+N5rOV5L2c55So5Z+f55qE5py655CG6YCa6L+H546v5aKD5a6e546w44CCDQoNCuWHveaVsOS8mOWFiOWcqOWGhemDqOeOr+Wig+aQnOe0oueUqOWIsOeahOWPmOmHj++8jOaQnOe0ouS4jeWIsOaXtu+8jOWwseWIsOS4iuS4gOe6p+eOr+Wig+aQnOe0ouOAgg0KDQrmr4/liqDovb3kuIDkuKrmianlsZXljIXvvIzov5nkuKrljIXnmoTnjq/looPpg73kvJrmj5LlhaXmkJzntKLot6/lvoTvvIzlubbkvY3kuo7lhajlsYDnjq/looPkuYvliY3jgIINCg0KfCDnjq/looPkuqTkupLlh73mlbAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB8DQp8IGBscygpYC9gb2JqZWN0cygpYCAgICAgICAgfCDliJflh7rlvZPliY3lt6XkvZznqbrpl7TnmoTmiYDmnInlr7nosaEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgYGxzLnN0cihtb2RlPSwgcGF0dGVybj0pYCB8IOaYvuekuuW9k+WJjeeOr+Wig+eahOe7k+aehOOAgm1vZGUg5Y+C5pWw6L+H5ruk5a+56LGh57G75Z6L77yMcGF0dGVybiDlj4LmlbDkuLrmraPliJnooajovr7lvI/vvIzov4fmu6Tlr7nosaHlkI0gfA0KfCBgcm0oKWAgICAgICAgICAgICAgICAgICAgIHwg5Yig6Zmk5LiA5Liq5oiW5pu05aSa5Liq5a+56LGh44CCICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBgcm0obGlzdD1scyhhbGw9VFJVRSkpYCAgIHwg5Yig6Zmk5omA5pyJ5a+56LGhICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgYGdldE9wdGlvbigpYCAgICAgICAgICAgICB8IOafpeeci+WFqOWxgOmAiemhuSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IGBvcHRpb25zKClgICAgICAgICAgICAgICAgfCDorr7lrprlhajlsYDpgInpobnjgILlpoIgZGlnaXRzPTcsIOiuvuWumuaYvuekuuaVsOWtl+eahOS9jeaVsOOAgndhcm49MCwg5Y+v5Lul5pS55Li6Me+8jOWcqOitpuWRiuS6p+eUn+aXtueri+WNs+aYvuekuuOAgiB8DQoNCiMjIyBQYXRoDQoNCnwgV29ya2luZyAgRGlyZWN0b3J5ICB8ICAgICAgICAgICAgICAgICAgICAgICB8DQp8IC0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0gfA0KfCBgZGlyLmNyZWF0ZSgpYCAgICAgIHwg5Yib5bu65LiA5Liq55uu5b2VICAgICAgICAgIHwNCnwgYGdldHdkKClgL2BzZXR3ZCgpYCB8IOafpeeciy/orr7lrprlvZPliY3lt6XkvZznm67lvZUgfA0KDQoNCg0KIyMjIE1lbW9yeQ0KDQpgdHJhY2VtZW0oKWDmn6XnnIvlr7nosaHnmoTlhoXlrZjlnLDlnYANCg0KIyMjIFRpbWUNCg0KYFN5cy5zbGVlcCgpYCDkvb/nqIvluo/mmoLlgZzoi6XlubLnp5LvvIzkuIDoiKznlKjkuo7mn5Dkupvlvqrnjq/vvIjniKzomavjgIHliqjnlLvnrYnvvInvvIzmlYXmhI/pmY3kvY7ov5DooYzpopHnjocNCg0KYHN5cy50aW1lKClgIOivu+WPluezu+e7n+aXtumXtA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCnQxIDwtIFN5cy50aW1lKCkNCi4uLg0KdDIgPC0gU3lzLnRpbWUoKQ0KcHJpbnQodDIgLSB0MSkgIyDkuK3pl7Tku6PnoIHnmoTov5DooYzml7bpl7QNCmBgYA0KDQoNCiMjIyBIZWxwDQoNCnwgSGVscCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfA0KfCBgaGVscChmdW5jdGlvbk5hbWUpYOaIlmA/ZnVuY3Rpb25OYW1lYCB8IOafpeeci+S4gOS4quWHveaVsOeahOeUqOazlSAgICAgICAgICAgICB8DQp8IGBleGFtcGxlKGZ1bmN0aW9uTmFtZSlgICAgICAgICAgICAgICAgfCDov5DooYzluK7kuLvmlofku7bkuK3nmoTkvovlrZAgICAgICAgICAgIHwNCnwgYGhlbHAuc2VhcmNoKGtleXdvcmQpYOaIlmA/P2tleXdvcmRgICAgfCDlnKg9PeaJgOacieWMhT0955qE5paH5qGj5Lit5pCc57Si5YWz6ZSu6K+NIHwNCnwgYGhlbHAocGFja2FnZSA9ICIiKWAgICAgICAgICAgICAgICAgICB8IOafpeeci+S4gOS4quWMheeahOW4ruWKqSAgICAgICAgICAgICAgIHwNCnwgYGhlbHAob3B0aW9ucylgICAgICAgICAgICAgICAgICAgICAgICB8IOaYvuekuuWPr+eUqOmAiemhueeahOivtOaYjiAgICAgICAgICAgICB8DQp8IGBvcHRpb25zKClgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCDmmL7npLrmiJborr7nva7lvZPliY3pgInpobkgICAgICAgICAgICAgfA0KDQojIyMgSGlzdG9yeQ0KDQp8IEhpc3RvcnkgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwNCnwgYGhpc3RvcnkoIylgICAgICAgICAgICAgfCDmmL7npLrmnIDov5Hkvb/nlKjov4fnmoQj5Liq5ZG95Luk77yI6buY6K6k5YC85Li6MjXvvIkgICAgICAgICAgIHwNCnwgYHNhdmVoaXN0b3J5KCJteWZpbGUiKWAgfCDkv53lrZjlkb3ku6Tljoblj7LliLDmlofku7ZteWZpbGXkuK3vvIjpu5jorqTlgLzkuLouUmhpc3RvcnnvvIkgfA0KfCBgbG9hZGhpc3RvcnkoIm15ZmlsZSIpYCB8IOi9veWFpeS4gOS4quWRveS7pOWOhuWPsuaWh+S7tu+8iOm7mOiupOWAvOS4ui5SaGlzdG9yee+8iSAgICAgICB8DQoNCg0KDQojIyBNb2R1bGFyaXphdGlvbg0KDQojIyMgUiBQYWNrYWdlDQoNCnwgUGFja2FnZSAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwNCnwgYGluc3RhbGwucGFja2FnZXMoInBhY2thZ2UiKWAgIHwg5a6J6KOF5YyFICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgYGluc3RhbGxlZC5wYWNrYWdlcygpYCAgICAgICAgIHwg6L+U5Zue5LiA5Liq5a2X56ym5Liy55+p6Zi177yM5YaF5ZCr5omA5pyJ5bey5a6J6KOF55qE5YyF55qE5aSa6aG55L+h5oGvICAgICAgICAgICAgICAgICB8DQp8IGBsaWJyYXJ5KClgICAgICAgICAgICAgICAgICAgICB8IOaXoOWPguaVsOaXtu+8jOaYvuekuuW6k+S4reW3sue7j+WuieijheS6huWTquS6m+WMhSAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgYGxpYnJhcnkocGFja2FnZSlgICAgICAgICAgICAgIHwg5pyJ5Y+C5pWw5pe277yM6L295YWl5YyFICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBgdW5sb2FkTmFtZXNwYWNlKHBhY2thZ2UpYCAgICAgfCDop6PpmaTovb3lhaXkuIDkuKrljIUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgYHNlYXJjaCgpYCAgICAgICAgICAgICAgICAgICAgIHwg5p+l55yL546v5aKD5Lit5bey57uP5Yqg6L295LqG5ZOq5Lqb5YyFICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IGBnZXRPcHRpb24oJ2RlZmF1bHRQYWNrYWdlcycpYCB8IOafpeeci+m7mOiupOWKoOi9veeahCBSIOWMhSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgYHVwZGF0ZS5wYWNrYWdlcygicGFja2FnZSIpYCAgIHwg5Y2H57qn5YyF44CC6Iul5LiN5aGr5YWl5Y+C5pWw77yM5YiZ6Ieq5Yqo5Y2H57qn5omA5pyJ5Y+v5Lul5Y2H57qn55qE5YyFICAgICAgICAgICAgIHwNCnwgYHBhY2thZ2U6OmZ1bmN0aW9uKClgICAgICAgICAgIHwg6LCD55So55u45bqU5YyF55qE5Ye95pWw77yI5pyJ5pe2KirlpJrkuKrljIXnlKjlkIzkuIDkuKrlkI3lrZflkb3lkI3kuI3lkIznmoTlh73mlbDvvIzkvJrlj5HnlJ/lhrLnqoHvvIzlj6rog73ov5nmoLflvJXnlKgqKu+8iSB8DQp8IGBkYXRhKClgICAgICAgICAgICAgICAgICAgICAgICB8IOafpeeci+aJgOaciemihOWFiOaPkOS+m+eahOaVsOaNriAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgYGRhdGEocGFja2FnZT0iIilgICAgICAgICAgICAgIHwg5p+l55yL5p+Q5Liq5YyF5omA5pyJ6aKE5YWI5o+Q5L6b55qE5pWw5o2uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBgZGF0YShkYXRhc2V0X25hbWUsIHBhY2thZ2U9KWAgfCDor7vlhaXljIXkuK3mlbDmja4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmluc3RhbGxlZC5wYWNrYWdlcygpICU+JSBWaWV3KCkNCmBgYA0KDQohW10oaHR0cDovL2h1bW9vbi1pbWFnZS1ob3N0aW5nLXNlcnZpY2Uub3NzLWNuLWJlaWppbmcuYWxpeXVuY3MuY29tL2ltZy90eXBvcmEvMjAyMi9pbWFnZS0yMDIyMDQwNDA1NTMyNTA5OS5wbmcpDQoNCiMjIyMg5paw6KOFIFIg5pe25a6J6KOF5bi455So5YyFDQoNCmBgYHtyfQ0KIyDph43oo4UgUiDliY3miorlt7Llronoo4XljIXnmoTlkI3np7DvvIjnrKzkuIDliJfvvInlrZjkuLrkuIDkuKogLnJkcyDmlofku7YNCmluc3RhbGxlZC5wYWNrYWdlcygpWywgMV0gJT4lIA0KCXNhdmVSRFMoIi4vZG93bmxvYWQtcGFja2FnZXMucmRzIikgDQpgYGANCg0KYGBgUg0KIyDph43oo4UgUiDlkI7or7vlj5bor6Xmlofku7bvvIzlubblronoo4Xov5nkupsgcGFja2FnZXMNCnJlYWRSRFMoIi4vZG93bmxvYWQtcGFja2FnZXMucmRzIikgJT4lIA0KCWluc3RhbGwucGFja2FnZXMoKQ0KYGBgDQoNCiMjIyMg5p+l55yL5YyF55qE5rWB6KGM56iL5bqmDQoNCmBgYHtyfQ0KIyDmn6XnnIsgUiDljIXnmoTkuIvovb3mrKHmlbANCmxpYnJhcnkoY3JhbmxvZ3MpDQoNCmZhc2hpb24gPC0gZnVuY3Rpb24ocGFja2FnZV9uYW1lKSB7DQogIGQgPC0gY3Jhbl9kb3dubG9hZHMoDQogICAgcGFja2FnZSA9IHBhY2thZ2VfbmFtZSwNCiAgICBmcm9tID0gIjIwMjItMDEtMDEiLA0KICAgIHRvID0gIjIwMjItMDMtMzEiDQogICkNCiAgc3VtKGQkY291bnQpDQp9DQoNCmZhc2hpb24oJ2dncGxvdDInKQ0KZmFzaGlvbigidGlkeXZlcnNlIikNCmZhc2hpb24oImRhdGEudGFibGUiKQ0KZmFzaGlvbigicGxvdGx5IikNCmBgYA0KDQojIyMgUiBTY3JpcHQNCg0KIyMjIyDor63ms5UNCg0KYHNvdXJjZSgneHh4LlInKWAgDQoNCiMjIyMg5pyA5L2z5a6e6Le1DQoNCueUseS6jiBSIOeahOaHkuWKoOi9veeJueaAp++8jOaooeWdl+S4reeahOS7o+eggeS4jeS8mui/kOihjO+8jOaVhSAuUiDohJrmnKzmlofku7bkvZzkuLrmqKHlnZfml7bvvIzkuI3lv4XliqDovb3phY3nva7luLjph4/lkozljIXvvIznuq/lhpnlh73mlbDljbPlj6/vvIzmiYDmnInnmoTljIXlkozphY3nva7nlLHkuLvmlofku7bliqDovb3jgIINCg0KDQoNCiMjIENvZGUgU3R5bGUNCg0KIyMjIOagvOW8j+WMlg0KDQojIyMjIHN0eWxlciDljIUNCg0KW3N0eWxlciAtIEEgbm9uLWludmFzaXZlIHNvdXJjZSBjb2RlIGZvcm1hdHRlciBmb3IgUiAobG9yZW56d2FsdGhlcnQuZ2l0aHViLmlvKV0oaHR0cHM6Ly9sb3Jlbnp3YWx0aGVydC5naXRodWIuaW8vc3R5bGVycG9zdC8pDQoNCmBgYFINCmluc3RhbGwucGFja2FnZXMoInN0eWxlciIpDQpgYGANCg0KLSBgc3R5bGVfdGV4dCgpYCBzdHlsZXMgYSBzdHJpbmcNCi0gYHN0eWxlX2ZpbGUoKWAgc3R5bGVzIFIgYW5kIFJtZCBmaWxlcw0KLSBgc3R5bGVfZGlyKClgIHN0eWxlcyBhbGwgUiBhbmQvb3IgUm1kIGZpbGVzIGluIGEgZGlyZWN0b3J5Lg0KLSAqKuacgOW4uOeUqCoqDQogIC0gUlN0dWRpbyBgQWRkaW5zYCDoj5zljZXvvIxzdHlsZXMgdGhlIGFjdGl2ZSBmaWxlIFIgb3IgUm1kIGZpbGUsIG9yIHRoZSBoaWdobGlnaHRlZCBjb2RlLg0KICAtIOaIluWcqCBjb25zb2xlIOS4rei+k+WFpWBzdHlsZXI6OjpzdHlsZV9hY3RpdmVfZmlsZSgpYA0KICANCg0KIyMjIEdvb2dsZSBSIFN0eWxlDQoNCiMjIyMg5LiA6Iis5oCn6KeE5YiZDQoNCi0g5bC96YeP6YG/5YWN5L2/55SoYGF0dGFjaCgpYCwgYGRldGFjaCgpYA0KLSBFcnJvciDlupTor6Xkvb/nlKhgU3RvcCgpYOadpeaKm+WHug0KLSBTMyDnsbvlkowgUzQg57G755qE5Ye95pWw5LiN6KaB5LiA6LW35L2/55SoDQoNCiMjIyMg5ZG95ZCNDQoNCuWvueixoeWRveWQjeS7peWPpeWPt2AuYOWIhumalO+8jOS4jeeUqOS4i+WIkue6vw0KDQrlh73mlbDlkI3pppblrZfmr43lpKflhpnvvIzpqbzls7DlvI/lkb3lkI3ms5XvvIzkuI3nlKjlj6Xlj7fliIbpmpQNCg0KIyMjIyDms6jph4oNCg0K5rOo6YeK6KGM5LulYCNg5byA5aS077yM5ZCO5Yqg5LiA5Liq56m65qC8DQoNCuS7o+eggeihjOWGheefreazqOmHiumcgOimgeWcqOS7o+eggeWQjumdouepuuS4pOagvO+8jOeEtuWQjmAjYO+8jOWGjeWKoOS4gOS4quepuuagvA0KDQoqKuWvueWPmOmHj+WSjOWHveaVsOeahOivtOaYjuWGmeWcqOWug+S7rOeahOS4iuaWue+8iOe0p+mCu++8ie+8jFZTQ29kZSDnmoQgUiDmj5Lku7bog73lpJ/oh6rliqjor4bliKsqKg0KDQojIyMjIOaAu+S9k+W4g+WxgOS4jumhuuW6jw0KDQoxLiDniYjmnYPlo7DmmI4NCjIuIOS9nOiAheS/oeaBrw0KMy4g5paH5Lu26K+05piOLCDljIXmi6znqIvluo/nmoTnm67nmoTvvIzovpPlhaXku6Xlj4rovpPlh7oNCjQuIHNvdXJjZSgpIOWSjCBsaWJyYXJ5KCkg6K+05piODQo1LiDlh73mlbDlrprkuYkNCjYuIOWPr+aJp+ihjOivreWPpSwg5aaC5p6c5pyJ55qE6K+dICjkvovlpoIsIHByaW50LCBwbG90KQ0KDQrljZXlhYPmtYvor5XlupTlnKjlj6bkuIDkuKrni6znq4vnmoTnmoTmlofku7bkuK3ov5vooYwNCg0KDQoNCiMjIElERQ0KDQojIyMgUnN0dWRpbw0KDQpbUiBTdHVkaW8gY2hlYXRzaGVldF0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3JzdHVkaW8vY2hlYXRzaGVldHMvbWFpbi9yc3R1ZGlvLWlkZS5wZGYpIOmihOiniO+8mg0KDQo8b2JqZWN0IGRhdGE9Ii4uL3BkZi9jaGVhdHNoZWV0LXJzdHVkaW8taWRlLnBkZiIgdHlwZT0iYXBwbGljYXRpb24vcGRmIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIj48L29iamVjdD4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQpkb3dubG9hZHRoaXM6OmRvd25sb2FkX2ZpbGUoDQogIHBhdGggPSAiLi4vcGRmL2NoZWF0c2hlZXQtcnN0dWRpby1pZGUucGRmIiwNCiAgb3V0cHV0X25hbWUgPSAiY2hlYXRzaGVldC1yc3R1ZGlvLWlkZSIsDQogIGJ1dHRvbl9sYWJlbCA9ICJEb3dubG9hZCBjaGVhdHNoZWV0IiwNCiAgYnV0dG9uX3R5cGUgPSAic3VjY2VzcyIsDQogIHNlbGZfY29udGFpbmVkID0gRkFMU0UNCikNCmBgYA0KDQojIyMjIFNob3J0Y3V0cw0KDQp8IFNob3J0Y3V0cyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwNCnwgQ3RybCArIFNoaWZ0ICsgQSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IOmAieS4remDqOWIhuihjOWQju+8jOagvOW8j+WMluS7o+eggSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IEN0cmwgKyBBbHQgKyBJICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBJbnNlcnQgY2h1bmsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBBbHQgKyAtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwg5o+S5YWlIDwtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBDdHJsICsgU2hpZnQgKyBNICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwg5o+S5YWlJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBBbHQgKyBTaGlmdCArIEsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwg5pi+56S65b+r5o236ZSuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBDdHJsICsgU2hpZnQgKyBOICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwg5paw5bu66ISa5pysIC5y5paH5Lu2ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgQ3RybCArIEVudGVyPGJyIC8+Q3RybCArIFNoaWZ0ICsgRW50ZXI8YnIgLz5DdHJsICsgQWx0ICsgUiB8IOi/kOihjOS4gOihjOS7o+eggTxiciAvPui/kOihjOS7o+eggeWdlzxiciAvPui/kOihjOWFqOmDqOS7o+eggSAgICAgICAgICAgICAgIHwNCnwgU2hpZnQgKyBIb21lL0VuZCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IOmAieS4reWFieagh+WIsOihjOmmli/mnKvkuYvpl7TnmoTpg6jliIYgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBUYWIgLyBDdHJsK1NwYWNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwg6Ieq5Yqo6KGl6b2QPGJyIC8+6L6T5YWl5a6M5Ye95pWw5ZCN77yM5oyJdGFi77yM6Ieq5Yqo5re75Yqg5byA5ous5Y+3KOWSjOmXreaLrOWPtynjgIIgfA0KfCBDdHJsICsgU2hpZnQgKyBDICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwg5rOo6YeKL+WPlua2iOazqOmHiiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgRjEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IOafpeeci+W4ruWKqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBDdHJsKyDihpEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCDlnKggQ29uc29sZSDkuK3ovpPlhaXigJx4eHjigJ3vvIznhLblkI7mjIkgQ3RybCsg4oaR44CC5bCx5Y+v5Lul5YiX5Ye65omA5pyJ6L6T5YWl6L+H55qE5Lul4oCceHh44oCd5byA5aS055qE5ZG95Luk44CCIHwNCg0KIyMjIyDku6PnoIHpq5jkuq4NCg0KR2l0SHViIOS4iuWPr+aQnOe0ouOAgeWuieijhSByc2NvZGVpbyDkuLvpopgNCg0KW2FudGhvbnlub3J0aC9yc2NvZGVpbzogQW4gUlN0dWRpbyB0aGVtZSBpbnNwaXJlZCBieSBWaXN1YWwgU3R1ZGlvIENvZGUuIChnaXRodWIuY29tKV0oaHR0cHM6Ly9naXRodWIuY29tL2FudGhvbnlub3J0aC9yc2NvZGVpbykNCg0KIyMjIFZTQ29kZQ0KDQojIyMjIOS8mOeCuQ0KDQotIOm8oOagh+aCrOWBnO+8jOWNs+WPr+aYvuekuuWPmOmHj+eahOWumuS5ieS/oeaBr+WSjOWHveaVsOeahOW4ruWKqeaWh+aho++8iOS7hemZkCBSIOWMheS4reWHveaVsOeahOWumOaWueaWh+aho+WSjOacrOaWh+S7tuS4reiHquWumuS5ieWHveaVsOeahOWumuS5ie+8jOaXoOazleaYvuekuuW8leWFpeaooeWdl+S4reeahOiHquWumuS5ieWHveaVsOeahOWumuS5ie+8ie+8jOecgeWOu+S6huafpemYheaWh+aho+eahOWkp+mHj+aXtumXtA0KLSDkv53lrZjvvIhgQ3RybCtTYO+8ieaXtuiHquWKqOagvOW8j+WMlg0KLSBgQ3RybCtFbnRlcmDoh6rliqjov5DooYzkuIDooYzvvIxgQ3RybCtTaGlmdCtFbnRlcmDoh6rliqjov5DooYzlvZPliY3mlofku7YNCg0KIyMjIyDphY3nva7mraXpqqQNCg0KMS4g5a6J6KOFIFIg5YyFIGxhbmd1YWdlc2VydmVyDQoNCiAgIGBgYFINCiAgIGluc3RhbGwucGFja2FnZXMoImxhbmd1YWdlc2VydmVyIikNCiAgIGBgYA0KDQoyLiDlnKggVlNDb2RlIOaJqeWxleWVhuW6l+S4reWuieijhSBSIOaPkuS7tuOAgg0KDQogICAxLiDlronoo4XlrozmiJDlkI7lnKggVlNDb2RlIOiuvue9ruS4reaQnOe0omByLnJ0ZXJtLm9wdGlvbmDvvIzliKDpmaRgLS1uby1zYXZlLC0tbm8tcmVzdG9yZWDvvIzmt7vliqBgLS1uby1zaXRlLWZpbGVg5ZKMIFIuZXhlIOeahOi3r+W+hGAtLXItYmluYXJ5PUM6XFByb2dyYW0gRmlsZXNcUlxSLTQuMS4zXGJpblxSLmV4ZWANCg0KMy4g5a6J6KOFIFJhZGlhbu+8muS4gOasvueOsOS7o+eahCBSIGNvbnNvbGXvvIzlroPmmK/nlKggUHl0aG9uIOe8luWGmeeahA0KDQogICBgYGBwb3dlcnNoZWxsDQogICBwaXAgaW5zdGFsbCByYWRpYW4NCiAgIGBgYA0KDQogICAxLiDlronoo4XlrozmiJDlkI7lnKggY21kIOS4rei+k+WFpSBgcmFkaWFuYCDmn6XnnIvmmK/lkKblronoo4XmiJDlip/jgIINCg0KICAgMi4g6Iul5Ye6546wIOKAnGNhbm5vdCBkZXRlcm1pbmUgUiBIT01F4oCd77yM5Y+v6IO95a2Y5Zyo5aSa5LiqUui3r+W+hO+8iOWmguaWsOWuieijheS6hjQuMS4y54mI5pys77yJ77yM6ICMIFJhZGlhbiDml6Dms5Xor4bliKvjgILop6PlhrPov5nkuKrpl67popjnmoTmlrnms5Xku43nhLbmmK/lnKggVlNDb2RlIOS4reiuvue9riBSLmV4ZSDnmoTot6/lvoTjgILpmaTkuobmkJzntKJgci5ydGVybS5vcHRpb25g6L+b6KGM5L+u5pS577yM5Lmf5Y+v5Lul5Zyo6K6+572u55WM6Z2i55qE5Y+z5LiK6KeS5omT5byAIHNldHRpbmcuanNvbuaWh+S7tuebtOaOpeS/ruaUue+8mg0KDQogICAgICBgYGBganNvbg0KICAgICAgICAici5ydGVybS5vcHRpb24iOiBbDQogICAgICAgICAgIi0tbm8tc2l0ZS1maWxlIiwNCiAgICAgICAgICAiLS1yLWJpbmFyeT1DOlxcUHJvZ3JhbSBGaWxlc1xcUlxcUi00LjEuM1xcYmluXFxSLmV4ZSINCiAgICAgICAgXSwNCiAgICAgIGBgYGANCg0KNC4gVlNDb2RlIOS4rSBSYWRpYW4g55u45YWz6K6+572uDQoNCiAgIDEuIOaQnOe0oiBgci5ydGVybS53aW5kb3dzYO+8jOWwhuWFtuiuvue9ruS4uiByYWRpYW4uZXhlIOeahOi3r+W+hOOAguWcqCBjbWQg5Lit77yIcG93ZXJzaGVsbCDkuI3ooYzvvInovpPlhaUgYHdoZXJlIHJhZGlhbmAg5Y+v5Lul6I635Y+W5YW26Lev5b6E44CCDQogICAyLiDmkJzntKJgUjogQnJhY2tldGVkIFBhc3RlYOW5tuWLvumAie+8jOWQpuWImSBSYWRpYW4g5LiN5Lya5ZCv55SoDQogICAzLiDmkJzntKJgci5zZXNzaW9uV2F0Y2hlcmDlubbli77pgIkNCg0KDQoNClvlpoLkvZXlnKggVlNDT0RFIOS4remrmOaViOS9v+eUqCBSIOivreiogCDvvIjlm77mlofor6bop6PvvIlfQmFpbW9jLUNTRE7ljZrlrqJdKGh0dHBzOi8vYmxvZy5jc2RuLm5ldC91MDExMjYyMjUzL2FydGljbGUvZGV0YWlscy8xMTM4Mzc3MjApDQo=